package com.hl.card.credit.utill;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.hl.card.credit.domain.CreditCardOrder;
import com.hl.card.credit.domain.InitailFormDTO;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.encoders.UrlBase64;
import com.alibaba.fastjson.JSONObject;

/**
 * DEMO为GET请求加密验签示例，
 * 请勿直接拷贝使用。
 * 请各位同事按需参考。
 *
 * @author YANGCHENBIN360
 */
public class PingAnTool {
    static String versionNo = "R10310";
    static String code = "m1804095435";
    static String code_test = "m1811155485";
    static String reserve = "00000";
    public  static String scc = "235180089";
    static String mt = "0000000000000000000";
    static String onlineSQFlag = "N";
    static String channel = "WXHZF";
    static String gurl = "https://pacesapplystg.pingan.com/ca/applyIndex";
    static String zgurl = "https://c.pingan.com/ca/applypIndex";
    static String purl = "https://pacesapplystg.pingan.com/ca/applypIndex";
    static String zpurl = "https://c.pingan.com/ca/applypIndex";
    /**
     * 链接拼接
     *
     * @param initDTO
     * @return
     */
    public static String getUrl(InitailFormDTO initDTO) {
        //sign加密KEY
        String secret = "Ued234fKsd3*45fLNs3-45dfk57s";
        //AES加密KEY
        String aesKey = "BWTAws7fQgOJlgLFK-xIhA..";
        String url = "";
        //data值 获取
        String data = paramData(initDTO, aesKey);
        if (isNullOrBlank(data)) {
            return "ERROR.";
        } else {
            System.out.println("data最终结果：" + data);
        }
        //sign值 获取
        String sign = paramSign(initDTO, secret);
        if (isNullOrBlank(sign)) {
            return "ERROR.";
        } else {
            System.out.println("验签最终结果：" + sign);
        }
        //生成最终URl（注意测试环境和生产环境 请求不同）
        url = "https://pacesapplystg.pingan.com/ca/applyIndex?" + "data=" + data + "&sign=" + sign;
        return url;
    }

    /**
     * 链接拼接正式环境
     * @param initDTO
     * @return
     */
    public static String getUrlReal(InitailFormDTO initDTO){
        //sign加密KEY
        String secret="YLPPA-WANGSHEN-595284-SECAP-@#$*^";
        //AES加密KEY
        String aesKey="ZCZZOcB3nQiAscNvQ1gdDQ..";
        String url="";
        //data值 获取
        String data=paramData(initDTO,aesKey);
        if (isNullOrBlank(data)) {
            return "ERROR.";
        }else{
            System.out.println("data最终结果："+data);
        }
        //sign值 获取
        String sign=paramSign(initDTO,secret);
        if (isNullOrBlank(sign)) {
            return "ERROR.";
        }else{
            System.out.println("验签最终结果："+sign);
        }
        //生成最终URl（注意测试环境和生产环境 请求不同）
        url= "https://c.pingan.com/ca/applyIndex?"+"data=" + data + "&sign=" + sign;
        return url;
    }

    /**
     * AES  获取data值
     * （key值顺序不一致，可能会导致加密结果不一致。可以收）
     *
     * @param initDTO
     * @param aesKey
     * @return
     */
    public static String paramData(InitailFormDTO initDTO, String aesKey) {
        //生成jason格式字段    直接使用gson，可能会更好
        String jsonParam = JSONObject.toJSONString(getJasonMap(initDTO));//字段转Json
        System.out.println("json格式结果：" + jsonParam);
        String result = encrypt(jsonParam, aesKey);//AES加密
        System.out.println("AES加密后结果：" + result);
        if (!isNullOrBlank(result)) {  //在最前面拼上9位的SCC和20位的mt参数值（mt参数如果不足20位用0补足），形成最终的密文数据。
            if (isNullOrBlank(initDTO.getMt())) {
                return initDTO.getScc() + "00000000000000000000" + result;
            } else {
                return initDTO.getScc() + StringUtils.leftPad(initDTO.getMt(), 20, '0') + result;
            }
        } else {
            return null;
        }
    }

    /**
     * HmacSHA256验签  获取sign值
     *
     * @param initDTO
     * @param aesKey
     * @return
     */
    public static String paramSign(InitailFormDTO initDTO, String secret) {
        String generateSign = null;
        try {
            Field[] fields = InitailFormDTO.class.getDeclaredFields();
            List<String> list = new ArrayList<String>();
            if (fields != null) {
                for (Field a : fields) {
                    String name = a.getName();
                    Method m = InitailFormDTO.class.getMethod("get" + name.substring(0, 1).toUpperCase() + name.substring(1));
                    if (!isNullOrBlank((String) m.invoke(initDTO))) {
                        list.add(name);
                    }
                }
                if (list.size() > 0) {
                    Collections.sort(list);//将所有参数按key的ASCII码从小到大排序
                    StringBuffer bf = new StringBuffer();
                    for (String key : list) {//使用&符号拼接
                        String value = (String) InitailFormDTO.class.getMethod("get" + key.substring(0, 1).toUpperCase() + key.substring(1)).invoke(initDTO);
                        bf.append("&");
                        bf.append(key);
                        bf.append("=");
                        bf.append(value);
                    }
                    //将最终的字符串转换成全大写，再使用HmacSHA256进行签名。
                    System.out.println("排序后拼接转大写：" + bf.substring(1).toString().toUpperCase());
                    generateSign = sign(bf.substring(1).toString().toUpperCase(), secret);
                }
            }
            return generateSign;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * AES加密
     * 参数使用json格式，
     * AES加密后再对加密后的字符串进行UrlBase64编码，
     *
     * @param data   需要加密的字符串
     * @param aesKey AES key
     * @return
     */
    public static String encrypt(String data, String aesKey) {
        try {
            if (isNullOrBlank(data) || isNullOrBlank(aesKey)) {
                System.out.println("AESUtil.encrypt data or aesKey is null.");
                return null;
            }
            byte[] aesByte = UrlBase64.decode(aesKey);
            SecretKeySpec skeySpec = new SecretKeySpec(aesByte, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] encryptedByte = cipher.doFinal(data.getBytes("utf-8"));
            return new String(UrlBase64.encode(encryptedByte));
        } catch (Exception e) {
            System.out.println("AESUtil.encrypt exception." + e);
            return null;
        }
    }

    /**
     * HmacSHA256加密
     * 请确保key值顺序排列
     *
     * @param value  需要加密的字符串
     * @param secret HmacSHA256 key
     * @return
     */
    public static String sign(String value, String secret) {
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            String hash = new String(UrlBase64.encode(sha256_HMAC.doFinal(value.getBytes("utf-8"))));
            return hash;
        } catch (Exception e) {
            System.out.println("Failed to generate the sign." + e);
            return null;
        }
    }

    public static boolean isNullOrBlank(String str) {
        if (str == null || str.equals("") || str.equals("null")) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断每个字段是否为空
     * 返回去除value的key值
     *
     * @param obj
     * @return
     */
    private static Map<String, String> getJasonMap(Object obj) {
        Field[] field = obj.getClass().getDeclaredFields();
        Map<String, String> returnMap = new HashMap<String, String>();
        try {
            for (int j = 0; j < field.length; j++) {
                String name = field[j].getName();
                // 过滤serialVersionUID字段
                if ("serialVersionUID".equals(name)) {
                    continue;
                }
                String name1 = name.substring(0, 1).toUpperCase() + name.substring(1);
                Method m = obj.getClass().getMethod("get" + name1);
                String value = (String) m.invoke(obj);
                if (!isNullOrBlank(value)) {
                    returnMap.put(name, value);
                }
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        return returnMap;
    }
    public static String getSeqId() {
        //17位日期
        Calendar nowtime = new GregorianCalendar();
        String strDateTime = "" + String.format("%04d", nowtime.get(Calendar.YEAR)) + "" +
                String.format("%02d", nowtime.get(Calendar.MONTH)+1) + "" +
                String.format("%02d", nowtime.get(Calendar.DATE)) + "" +
                String.format("%02d", nowtime.get(Calendar.HOUR)) + "" +
                String.format("%02d", nowtime.get(Calendar.MINUTE)) + "" +
                String.format("%02d", nowtime.get(Calendar.SECOND)) + "" +
                String.format("%03d", nowtime.get(Calendar.MILLISECOND)) + "";
        //随机4位数
        int rand = (int) ((Math.random() * 9 + 1) * 1000);
        return code + reserve + strDateTime + rand;
    }
    public static String getSeqId(String Mcode) {
        //17位日期
        Calendar nowtime = new GregorianCalendar();
        String strDateTime = "" + String.format("%04d", nowtime.get(Calendar.YEAR)) + "" +
                String.format("%02d", nowtime.get(Calendar.MONTH)+1) + "" +
                String.format("%02d", nowtime.get(Calendar.DATE)) + "" +
                String.format("%02d", nowtime.get(Calendar.HOUR)) + "" +
                String.format("%02d", nowtime.get(Calendar.MINUTE)) + "" +
                String.format("%02d", nowtime.get(Calendar.SECOND)) + "" +
                String.format("%03d", nowtime.get(Calendar.MILLISECOND)) + "";
        //随机4位数
        int rand = (int) ((Math.random() * 9 + 1) * 1000);
        return Mcode + reserve + strDateTime + rand;
    }
    public static String getTestSeqId() {
        //17位日期
        Calendar nowtime = new GregorianCalendar();
        String strDateTime = "" + String.format("%04d", nowtime.get(Calendar.YEAR)) + "" +
                String.format("%02d", nowtime.get(Calendar.MONTH)+1) + "" +
                String.format("%02d", nowtime.get(Calendar.DATE)) + "" +
                String.format("%02d", nowtime.get(Calendar.HOUR)) + "" +
                String.format("%02d", nowtime.get(Calendar.MINUTE)) + "" +
                String.format("%02d", nowtime.get(Calendar.SECOND)) + "" +
                String.format("%03d", nowtime.get(Calendar.MILLISECOND)) + "";
        //随机4位数
        int rand = (int) ((Math.random() * 9 + 1) * 1000);
        return code_test + reserve + strDateTime + rand;
    }
    public static Map getOrderStatus(CreditCardOrder order){
        Map map=new HashMap();
        String currentStatus="订单未完成";
        int status=0;//初始订单
        if(null==order){
            map.put("currentStatus",currentStatus);
            map.put("status",status);
            return map;
        }
        if(order.getApplycompleted()!=null&& order.getApplycompleted().equals("P")){
            currentStatus="申请中";
            status=1;
        }else {
            currentStatus="申请未通过";
            status=-1;
        }
        if(order.getApplicationstatus()!=null&&order.getApplicationstatus().equals("P")){
            currentStatus="审批通过";
            status=2;
        }
        if(order.getMailed()!=null&&order.getMailed().equals("P")){
            currentStatus="已寄出";
            status=3;
        }
        if(order.getActivated()!=null&&order.getActivated().equals("P")){
            currentStatus="已激活";
            status=4;
        }
        if(order.getFirstused()!=null&&order.getFirstused().equals("P")){
            currentStatus="已首刷";
            status=5;
        }
        map.put("currentStatus",currentStatus);
        map.put("status",status);
        return map;
    }
    public static void main(String[] args) {
        String url = "";
        InitailFormDTO initDTO = new InitailFormDTO();
        /***************************参数赋值，请和业务确定*********************************************/
        initDTO.setPartnerSeqId("m180320106300000201804191255555271111");
        initDTO.setScc("920000999");
        initDTO.setTemplateNo("s180419Oot");
        initDTO.setMt("123456789");
        initDTO.setCcp("1a2a3a9");
        initDTO.setVersionNo("R10310");
        initDTO.setOnlineSQFlag("N");
        initDTO.setCardCatenaNo("01a02a04");
        initDTO.setChannel("WXHZF");
        /***************************中文记得转码UTF-8*************************************************/
        System.out.println("需要加密的入参:" + initDTO);
        url = getUrl(initDTO);
        System.out.println("最终生成测试环境url：" + url);
        /**
         * 结果：
         * 需要加密的入参:InitailFormDTO [versionNo=R10310, scc=920000999, onlineSQFlag=N, channel=WXHZF, cardCatenaNo=01a02a04, ccp=1a2a3a9, cf=null, cc=null, salesName=null, salesCode=null, salesmanPhoneNO=null, bt1=null, bt2=null, bt3=null, bt4=null, bt5=null, bt6=null, bt7=null, bt8=null, bt9=null, bt10=null, mt=123456789, recommendChineseName=null, recommendPhone=null, isDisplayRecommend=null, isDisplaySales=null, onePlusOneWB=null, onePlusOneYL=null, url=null, templateNo=s180419Oot, partnerSeqId=m180320106300000201804191255555271111, idCardStatus=null, partnerInfoIndex=null, salesmanType=null, hasZiGeSaleMan=null]
         * json格式结果：{"partnerSeqId":"m180320106300000201804191255555271111","scc":"920000999","templateNo":"s180419Oot","mt":"123456789","ccp":"1a2a3a9","versionNo":"R10310","onlineSQFlag":"N","cardCatenaNo":"01a02a04","channel":"WXHZF"}
         * AES加密后结果：Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.
         * data最终结果：92000099900000000000123456789Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.
         * 排序后拼接转大写：CARDCATENANO=01A02A04&CCP=1A2A3A9&CHANNEL=WXHZF&MT=123456789&ONLINESQFLAG=N&PARTNERSEQID=M180320106300000201804191255555271111&SCC=920000999&TEMPLATENO=S180419OOT&VERSIONNO=R10310
         * 验签最终结果：iMMUARHZgiCRSzKOfp0dJ0-pbxCbH7eoPmB3eKj2nGs.
         * 最终生成测试环境url：https://pacesapplystg.pingan.com/ca/applyIndex?data=92000099900000000000123456789Ke19Ek_N6FrJf6KCOjodGViA2Dapm1GRjcog4mupkeskTmfa1VHvY9F5TBLyBBqxtykc9AGBSbOkkEG-GdB9bcBd6iWj2GmmMX5WxL1XtcRxVRW081AeLgKz_jVmVKfk-Wkl2g-Fzky57ChiGTZ8begt0BKM4a4623HRuXuVCVHFpeKjTCMVS7iLaem4uRJVslBx_Yd5gGQLLHk-qH2C6CPBd-OgOv6Kp4e05L4tioAj5X-bxSsMdQsgoctjBCu28jI8_DUEFBrANyuFBEUqKfbAVVQwFefZBMmFEc11FBo.&sign=iMMUARHZgiCRSzKOfp0dJ0-pbxCbH7eoPmB3eKj2nGs.
         */

    }
}
